home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / WDFTST__ / TEXTDISP.C < prev    next >
C/C++ Source or Header  |  1990-06-12  |  11KB  |  377 lines

  1. #include <string.h>
  2. #include <stdarg.h>
  3. #include <stdio.h>
  4. #include <MacProto.h>
  5.  
  6. #include "TextDisplay.h"
  7.  
  8. /* =====================================================================
  9.     TextDisplay provides a window for the display of non-editable text.
  10. The idea is similar to THINK C's console window, except that TextDisplay
  11. windows are scrollable.  The console window also takes care of more stuff
  12. behind your back, which can be good for quick and dirty projects but can
  13. get in the way once you start to learn the toolbox.
  14.  
  15. Call TD_new once to create a TextDisplay window.  It returns a WindowPtr,
  16. which you can use like any other WindowPtr.  The window it returns is
  17. initially hidden, giving you a chance to move it or resize it before
  18. showing it, but you must remember to show it with ShowWindow.
  19.  
  20. Call TD_activate on every activate/deactivate or suspend/resume event,
  21. with a second parameter of TRUE or FALSE according to whether the window
  22. is activating.  You don't need to check whether the event is for the
  23. TextDisplay window or some other window, TD_activate checks that.  You
  24. should do a SetPort to the window being activated/deactivated before
  25. calling TD_activate, however.
  26.  
  27. For best results, also call TD_activate before showing a modal dialog
  28. or alert.
  29.  
  30. Call TD_update whenever you handle an update event.
  31.  
  32. Call TD_click when you receive a mousedown event in the content region of
  33. a window.  This is for scrolling.
  34.  
  35. Call TD_resize after you grow or zoom a window.
  36.  
  37. Finally, TD_printf actually puts text in the window.  Its first parameter
  38. is a pointer to a TextDisplay window, and its other parameters are
  39. those of printf.
  40.  
  41. In this sample, the TextDisplay window uses a custom WDEF for a movable,
  42. resizable window without a title bar.  You could use an ordinary window,
  43. but then you would have to be careful about how you draw the grow icon.
  44. My custom WDEF has the unusual feature that the grow region is part of the
  45. window frame, so it is always drawn automatically.
  46. ======================================================================= */
  47.  
  48. /* ----------------- Prototypes of private routines ------------------ */
  49. void    High_hook( void );
  50. void    TD_adjust_scrollbar_max( WindowPtr the_display, TEHandle the_text,
  51.             ControlHandle the_bar );
  52. void    Adjust_text( TEHandle the_text, ControlHandle the_bar );
  53. pascal void Scroll_text( ControlHandle what, int part_code );
  54. void    Handle_scroll( TEHandle the_text, int the_part, Point where,
  55.             ControlHandle scrollbar );
  56. pascal    Boolean Auto_scroll( void );
  57.  
  58.  
  59. /* ------------------------- TD_new ----------------------------- */
  60. WindowPtr TD_new(
  61.     int        window_id,        /* ID of WIND resource */
  62.     int        max_text,        /* keep at most this many characters */
  63.     int        min_text,        /* don't discard any text before this */
  64.     int        text_size,        /* font size */
  65.     OsErr    *status )        /* error code */
  66. {
  67.     WindowPtr    the_window;
  68.     Handle        a_handle;
  69.     Rect        dest_rect, view_rect;
  70.     TEHandle    text_h;
  71.     ControlHandle    the_bar;
  72.     Ptr            window_storage;
  73.     
  74.     /* Enough memory? */
  75.     if (max_text > MaxBlock())
  76.     {
  77.         *status = memFullErr;
  78.         return nil;
  79.     }
  80.     
  81.     /* First, get a window. */
  82.     a_handle = GetResource( 'WIND', window_id );
  83.     if ( (ResError() != noErr) || (a_handle == nil) )
  84.     {
  85.         *status = ResError();
  86.         return nil;
  87.     }
  88.     window_storage = NewPtr( sizeof(TD_record) );
  89.     if (MemError() != noErr)
  90.     {
  91.         *status = MemError();
  92.         return nil;        
  93.     }
  94.     the_window = GetNewWindow( window_id, window_storage, (WindowPtr)-1L );
  95.     SetPort( the_window );
  96.     TextSize( text_size );
  97.     
  98.     ((TD_peek)the_window)->max_text = max_text;
  99.     ((TD_peek)the_window)->min_text = min_text;
  100.     
  101.     /* Get a TE record. */
  102.     dest_rect = view_rect = the_window->portRect; /* Adjust later */
  103.     ((TD_peek)the_window)->text = text_h = TENew( &dest_rect, &view_rect );
  104.     (**text_h).highHook = (ProcPtr)High_hook;
  105.     
  106.     /* Make a scroll bar. */
  107.     the_bar = NewControl( the_window, &dest_rect, "\p", FALSE,
  108.         0, 0, 0, scrollBarProc, 0L );
  109.     TD_resize( the_window );
  110.     
  111.     TEAutoView( TRUE, text_h );    /* Permit auto-scrolling */
  112.     SetClikLoop( (ProcPtr)Auto_scroll, text_h );
  113.     ShowControl( the_bar );
  114.     *status = noErr;
  115.     return the_window;
  116. }
  117.  
  118. /* ------------------------ TD_printf --------------------------- */
  119. void TD_printf( WindowPtr the_display, char *format, ... )
  120. {
  121.     va_list        arg_ptr;
  122.     char        str[256];
  123.     int            i;
  124.     register int    amount_to_keep;
  125.     register int    line_len;
  126.     int                max_text;
  127.     TEHandle        the_text;
  128.     ControlHandle    the_bar;
  129.     
  130.     va_start( arg_ptr, format );
  131.     i = vsprintf( str, format, arg_ptr ); /* Find string to display. */
  132.     va_end( arg_ptr );
  133.     for (i--; i >= 0; i--)    /* Convert newlines to carriage returns. */
  134.         if (str[i] == '\n')
  135.             str[i] = '\r';
  136.     
  137.     
  138.     line_len = strlen(str);
  139.     the_text = ((TD_peek)the_display)->text;
  140.     the_bar = ((WindowPeek)the_display)->controlList;
  141.     max_text = ((TD_peek)the_display)->max_text;
  142.     
  143.     /*
  144.         Is there enough room in our text block? if not shift the text
  145.         up in the block.
  146.     */
  147.     if ( (**the_text).teLength > max_text - line_len )
  148.     {
  149.         amount_to_keep = ((TD_peek)the_display)->min_text;
  150.         if ( amount_to_keep > (max_text - line_len) )
  151.             amount_to_keep = max_text - line_len;
  152.         TESetSelect( 0L, (long)((**the_text).teLength - amount_to_keep),
  153.             the_text );
  154.         TEDelete( the_text );
  155.     }
  156.  
  157.     TESetSelect( (long)(**the_text).teLength, (long)(**the_text).teLength,
  158.         the_text );
  159.     TEInsert( str, (long)line_len, the_text );
  160.     TEPinScroll( 0, -1000, the_text );
  161.     TD_adjust_scrollbar_max( the_display, the_text, the_bar );
  162.     SetCtlValue( the_bar, GetCtlMax( the_bar ) );
  163. }
  164.  
  165. /* ---------------------- TD_resize ----------------------------------- */
  166. void TD_resize( WindowPtr the_display )
  167. {
  168.     register TEHandle    the_text;
  169.     ControlHandle        the_bar;
  170.     
  171.     if ((WindowPtr)thePort == the_display)
  172.     {
  173.         the_text = ((TD_peek)the_display)->text;
  174.         the_bar = ((WindowPeek)the_display)->controlList;
  175.         
  176.         (**the_text).viewRect = thePort->portRect;
  177.         (**the_text).viewRect.right -= GROW_ICON_SIZE;
  178.         (**the_text).viewRect.bottom -= TEXT_MARGIN;
  179.         (**the_text).viewRect.top += TEXT_MARGIN;
  180.         (**the_text).destRect = (**the_text).viewRect;
  181.         InsetRect( &(**the_text).destRect, TEXT_MARGIN, 0 );
  182.         TECalText( the_text );
  183.         TD_adjust_scrollbar_max( the_display, the_text, the_bar );
  184.         Adjust_text( the_text, the_bar );
  185.         
  186.         MoveControl( the_bar,
  187.             thePort->portRect.right - GROW_ICON_SIZE + 1, -1 );
  188.         SizeControl( the_bar, GROW_ICON_SIZE,
  189.             thePort->portRect.bottom - GROW_ICON_SIZE + 3 );
  190.     }
  191. }
  192.  
  193. /* ---------------------- TD_activate ------------------------ */
  194. void TD_activate( WindowPtr the_display, Boolean activate )
  195. {
  196.     Rect    scrollrect;
  197.     ControlHandle    the_bar;
  198.     int        old_hilite, new_hilite;
  199.     
  200.     if (thePort == the_display)
  201.     {
  202.         the_bar = ((WindowPeek)the_display)->controlList;
  203.         scrollrect = (**the_bar).contrlRect;
  204.         old_hilite = (**the_bar).contrlHilite;
  205.         new_hilite = activate? ACTIVE : INACTIVE;
  206.         if (old_hilite != new_hilite)
  207.         {
  208.             HiliteControl( the_bar, new_hilite );
  209.             ValidRect( &scrollrect );
  210.         }
  211.         /*    Under certain circumstances, this routine may be called to
  212.             deactivate the window when it's already inactive.
  213.             HiliteControl does not redraw a control if the hilite
  214.             value doesn't change, so in that case we should not
  215.             validate the scroll bar. 
  216.         */
  217.     }
  218. }
  219.  
  220. /* --------------------- TD_update ---------------------------- */
  221. void TD_update( WindowPtr the_display )
  222. {
  223.     register TEHandle    the_text;
  224.     
  225.     if ((WindowPtr)thePort == the_display)
  226.     {
  227.         the_text = ((TD_peek)the_display)->text;
  228.         TEUpdate( &(**the_text).viewRect, the_text );
  229.     }
  230. }
  231.  
  232. /* -------------------- TD_click ------------------------------ */
  233. void TD_click( WindowPtr the_display, Point where )
  234. {
  235.     Point local_point;
  236.     int        the_part;
  237.     ControlHandle    the_control;
  238.     register TEHandle    the_text;
  239.     
  240.     if ((WindowPtr)thePort == the_display)
  241.     {
  242.         the_text = ((TD_peek)the_display)->text;
  243.         local_point = where;
  244.         GlobalToLocal( &local_point );
  245.         the_part = FindControl( local_point, thePort, &the_control );
  246.         if (the_part)
  247.             Handle_scroll( the_text, the_part, local_point,
  248.                 ((WindowPeek)the_display)->controlList );
  249.         TEDeactivate( the_text );
  250.         TEClick( local_point, FALSE, the_text );
  251.     }
  252. }
  253.  
  254. void foo( void );
  255. /* ----------------------- High_hook ------------------------------ */
  256. /* 
  257.     The highHook routine is called by TextEdit to highlight the selection
  258.     range.  In this case I want no highlighting.
  259. */
  260. void foo(){
  261.     asm {
  262.         extern High_hook:
  263.         ADDQ.L    #4,SP    /* Throw away the argument, the address of a Rect */
  264.         RTS
  265.     }
  266. }
  267.  
  268. /* ------------------- TD_adjust_scrollbar_max -------------------------- */
  269. void TD_adjust_scrollbar_max( WindowPtr the_display,
  270.     TEHandle the_text, ControlHandle the_bar )
  271. {
  272.     int        window_height;
  273.     int     lines_above;
  274.     
  275.     window_height = ( (**the_text).viewRect.bottom
  276.         - (**the_text).viewRect.top ) / (**the_text).lineHeight;
  277.     lines_above = (**the_text).nLines - window_height;
  278.     if (lines_above <= 0)
  279.     {
  280.         HiliteControl( the_bar, INACTIVE );
  281.         lines_above = 0;
  282.     }
  283.     else if ( the_display == FrontWindow() )
  284.         HiliteControl( the_bar, ACTIVE );
  285.     SetCtlMax( the_bar, lines_above );
  286. }
  287.  
  288. /* ---------------------- Handle_scroll -------------------------------- */
  289. void Handle_scroll( TEHandle the_text, int the_part, Point where,
  290.     ControlHandle the_bar )
  291. {
  292.     if (the_part == inThumb)
  293.     {
  294.         (void) TrackControl( the_bar, where, nil );
  295.         Adjust_text( the_text, the_bar );
  296.     }
  297.     else
  298.         (void) TrackControl( the_bar, where, (ProcPtr)Scroll_text );
  299. }
  300.  
  301. /* ---------------------- Adjust_text ----------------------------- */
  302. void Adjust_text( TEHandle the_text, ControlHandle the_bar )
  303. {
  304.     int old_scroll, new_scroll;
  305.     
  306.     old_scroll = (**the_text).viewRect.top - (**the_text).destRect.top;
  307.     new_scroll = GetCtlValue( the_bar ) * (**the_text).lineHeight;
  308.     TEScroll( 0, old_scroll - new_scroll, the_text );
  309. }
  310.  
  311. /* ------------------------ Scroll_text ----------------------------- */
  312. pascal void Scroll_text( ControlHandle the_bar, int part_code )
  313. {
  314.     int        delta, old_value;
  315.     WindowPtr    the_display;
  316.     TEHandle    the_text;
  317.     
  318.     if (part_code != 0)
  319.     {
  320.         the_display = (**the_bar).contrlOwner;
  321.         the_text = ((TD_peek)the_display)->text;
  322.         
  323.         switch (part_code)
  324.         {
  325.             case inUpButton:
  326.                 delta = -1;
  327.                 break;
  328.             case inDownButton:
  329.                 delta = 1;
  330.                 break;
  331.             case inPageUp:
  332.                 delta = ( (**the_text).viewRect.top
  333.                     - (**the_text).viewRect.bottom )
  334.                     / (**the_text).lineHeight + 1;
  335.                 break;
  336.             case inPageDown:
  337.                 delta = ( (**the_text).viewRect.bottom
  338.                     - (**the_text).viewRect.top )
  339.                     / (**the_text).lineHeight - 1;
  340.                 break;
  341.         }
  342.         old_value = GetCtlValue( the_bar );
  343.         if ( ((delta < 0) && (old_value > 0)) ||
  344.             ((delta > 0) && (old_value < GetCtlMax(the_bar))) )
  345.             SetCtlValue( the_bar, old_value + delta );
  346.         Adjust_text( the_text, the_bar );
  347.     }
  348. }
  349.  
  350. /* ------------------------- Auto_scroll ----------------------------- */
  351. pascal Boolean Auto_scroll()
  352. {
  353.     Point    mouse_point;
  354.     Rect    view_rect;
  355.     RgnHandle    save_clip;
  356.     WindowPtr    the_display;
  357.     TEHandle    the_text;
  358.     ControlHandle    the_bar;
  359.     
  360.     the_display = FrontWindow();
  361.     the_text = ((TD_peek)the_display)->text;
  362.     the_bar = ((WindowPeek)the_display)->controlList;
  363.     
  364.     save_clip = NewRgn();
  365.     GetClip( save_clip );
  366.     ClipRect( &the_display->portRect );
  367.     GetMouse( &mouse_point );
  368.     view_rect = (**the_text).viewRect;
  369.     if (mouse_point.v < view_rect.top)
  370.         Scroll_text( the_bar, inUpButton );
  371.     else if (mouse_point.v > view_rect.bottom)
  372.         Scroll_text( the_bar, inDownButton );
  373.     SetClip( save_clip );
  374.     DisposeRgn( save_clip );
  375.     return TRUE;
  376. }
  377.